# -*-coding:utf-8-*-

import json

from tornado.gen import coroutine, Return

from pyrestful import mediatypes
from pyrestful.rest import get, post, put, delete
from utils.auth import authenticated
from handlers.base import BaseHandler
import functools
from bson.objectid import ObjectId


class PlatformUsersHandler(BaseHandler):
    def __init__(self, application, request, **kwargs):
        super(PlatformUsersHandler, self).__init__(application, request, **kwargs)
        self.delegate_name = 'users'

    def check_permissions(self, permissions):
        return True

    def check_user_id_from_path(self, user_id):
        if user_id != self.user_id:
            self.respond_error('invalid_path', 'user id not match')

    @coroutine
    def get_role_names_by_ids(self, role_ids):
        roles_of_member = role_ids
        roles_of_user = self.user.roles
        sub_roles_of_user = []
        for rid in roles_of_user:
            result = yield self.roles_dao.get_role_subordinates(self.user_id, rid)
            sub_roles_of_user += [x['role_id'] for x in result]
        if not set(roles_of_member).issubset(sub_roles_of_user):
            result = yield self.roles_dao.get_role_list_by_ids(sub_roles_of_user)
            self.respond_error('invalid_roles', 'supported roles: %s' % str(result))
        result = yield self.roles_dao.get_role_list_by_ids(roles_of_member)
        role_names = [x['name'] for x in result]
        raise Return(role_names)

    def phonecheck(self, s):
        phoneprefix = ['130', '131', '132', '133', '134', '135', '136', '137', '138', '139',
                       '150', '151', '152', '153', '156', '158', '159',
                       '170',
                       '183', '182', '185', '186', '188', '189']
        # return (len(s) == 11 and s.isdigit() and s[:3] in phoneprefix)
        if len(s) != 11 or not s.isdigit():
            self.respond_error('invalid_receive_number')

    @post(_path='/platform/api/users/{uid}/members', _types=[str],
          _consumes=mediatypes.APPLICATION_JSON)
    @authenticated
    @coroutine
    def create_user_member(self, uid, request):
        self.check_user_id_from_path(uid)
        self.phonecheck(request['username'])

        required_fields = ['roles', 'name', 'username', 'password']
        optional_fields = ['specifics', 'appkey']
        request = self.extract_fields(request, required_fields=required_fields, optional_fields=optional_fields)

        specifics = request.pop('specifics') if 'specifics' in request else {}
        kwargs = dict(specifics=specifics)
        kwargs['role_names'] = yield self.get_role_names_by_ids(request['roles'])
        kwargs['target'] = 'member'

        specifics = yield self.delegate_pre_create(self.delegate_name, **kwargs)
        if specifics is not None:
            request['specifics'] = specifics
        if 'appkey' in request:
            app = yield self.apps_dao.get_app(request.pop('appkey'))
            # 注意：相当于设置 app 的 developer_id/owner/vendor
            request.update(_id=ObjectId(app.developer_id))
        else:
            app = self.app
        result = yield self.users_dao.create_user_member(app, self.user_id, request)
        if result is None:
            self.respond_error('user_already_exists')
        self.respond_success(result)

    @coroutine
    def get_user_member_list(self, get_count=False):
        kwargs = self.query_arguments()

        roles_of_user = self.user.roles
        result = yield self.roles_dao.get_role_list_by_ids(roles_of_user)
        role_names = [x['name'] for x in result]
        kwargs.update(role_names=role_names)
        # NOTE: 根据用户角色，强制限定查询条件
        if 'root' in role_names:
            if 'appkey' in kwargs:
                app = yield self.apps_dao.get_app(kwargs.pop('appkey'))
                kwargs['app_id'] = app.id_str
        else:
            kwargs['app_id'] = self.app.id_str
        # 过滤出合法的 role ids
        if 'roles' in kwargs:
            siblings = []
            for rid in roles_of_user:
                result = yield self.roles_dao.get_role_siblings(self.user_id, rid)
                siblings.extend([x['role_id'] for x in result])
            result = yield self.roles_dao.get_role_subordinates(self.user_id, rid)
            subordinates = [x['role_id'] for x in result]
            roles = set(kwargs['roles'].split(',')) & (set(siblings) | set(subordinates))
            roles = list(roles)
            kwargs.update(roles=roles)

        filter_cond, projection = yield self.delegate_pre_get_list(self.delegate_name, **kwargs)
        print kwargs, filter_cond, projection, self.delegate_name, self.app.appkey
        if get_count:
            count = yield self.users_dao.count(filter_cond)
            result = dict(count=count)
        else:
            result = yield self.users_dao.get_paging_result(filter_cond, projection, 'user_id', None, **kwargs)
        raise Return(result)

    @get(_path='/platform/api/users/{uid}/{aspect}', _types=[str, str], _produces=mediatypes.APPLICATION_JSON)
    @authenticated
    @coroutine
    def get_user_aspect(self, uid, aspect):
        self.check_user_id_from_path(uid)
        if 'members' == aspect:
            result = yield self.get_user_member_list()
        elif 'roles' == aspect:
            rids = yield self.users_dao.get_user_role_list(self.user_id)
            result = yield self.roles_dao.get_role_list_by_ids(rids)
        else:
            raise Exception('Unsupported aspect')
        self.respond_success(result)

    @get(_path='/platform/api/users/{uid}/members/{aspect}', _types=[str, str])
    @authenticated
    @coroutine
    def get_user_member_aspect(self, uid, aspect):
        self.check_user_id_from_path(uid)
        if 'count' == aspect:
            result = yield self.get_user_member_list(get_count=True)
        else:
            mid = aspect
            result = yield self.users_dao.get_user_member(uid, mid)
        self.respond_success(result)

    @put(_path='/platform/api/users/{uid}/members/{mid}', _types=[str, str],
         _consumes=mediatypes.APPLICATION_JSON)
    @authenticated
    @coroutine
    def update_user_member(self, uid, mid, request):
        self.check_user_id_from_path(uid)
        specifics = request.pop('specifics') if 'specifics' in request else {}
        kwargs = dict(specifics=specifics)
        if 'roles' in request:
            kwargs['role_names'] = yield self.get_role_names_by_ids(request['roles'])
        handle_update = functools.partial(self.users_dao.update_user_member, uid, mid)
        result = yield self.delegate_update(self.delegate_name, handle_update, request, **kwargs)
        self.respond_success(result)

    @delete(_path='/platform/api/users/{uid}/members/{mid}', _types=[str, str])
    @authenticated
    @coroutine
    def delete_user_member(self, uid, mid):
        self.check_user_id_from_path(uid)
        result = yield self.users_dao.delete_user_member(uid, mid)
        self.respond_success(result)
